import uuid
from datetime import datetime, timedelta

from flask import request, jsonify, g

from aab import app
from aab.model import User, db, Roles, Group, Dwdm
from aab.settings import config
from aab.utils import generate_token, hash_password, AuthData, success, login_required, jsonify_error


@app.route('/login', methods=['POST'])
def login():
    data = request.get_json()
    if data is None:
        return jsonify_error(400, message='Require JSON data', is_login=True)

    user_number = data['user_number']
    password = data['password']
    user = User.query.filter_by(number=user_number).scalar()
    if user is None:
        return jsonify_error(401, message="登录失败", is_login=True)

    if hash_password(user.salt + password) != user.password:
        return jsonify_error(401, message="登录失败", is_login=True)

    now = datetime.now()
    expire_time = now + timedelta(hours=config.web.secret_hours)
    role = user.role
    group = user.group.name
    department = user.department.dm if user.department else None

    token = generate_token(AuthData(user_number, group, role), expire_time)
    return jsonify({
        'token': token,
        'role': role,
        'group': group,
        'department': department,
        'expire_time': expire_time.isoformat()
    })


@app.route('/logout', methods=['POST', 'GET'])
def logout():
    return success()


@app.route('/user/<user_number>/reset-password', methods=['POST'])
@login_required(roles=[Roles.ADMIN])
def reset_password(user_number):
    user = User.query.filter_by(number=user_number).scalar()
    if user is None:
        return jsonify_error(403, message='用户不存在')

    user.password = hash_password(user.salt + user.number)
    db.session.commit()
    return success()


@app.route('/user/<user_number>/change-password', methods=['POST'])
@login_required
def change_password(user_number):
    data = request.get_json()
    if data is None:
        return jsonify_error(400, message='Require JSON data')

    if g.auth.user_number != user_number:
        return jsonify_error(403, message="只能改自己的密码")

    user = User.query.filter_by(number=user_number).scalar()
    if user is None:
        return jsonify_error(403, message='密码验证失败')

    old_password = data['oldPassword']
    new_password = data['newPassword']

    if hash_password(user.salt + old_password) != user.password:
        return jsonify_error(403, message="密码验证失败")

    user.password = hash_password(user.salt + new_password)
    db.session.commit()
    return success()


@app.route('/users')
@login_required(roles=[Roles.ADMIN])
def query_users():
    users = User.query.all()
    return jsonify([user.to_dict() for user in users])


@app.route('/user/<user_number>')
@login_required(roles=[Roles.ADMIN])
def query_user(user_number):
    user = User.query.filter_by(number=user_number).scalar()
    return user.to_dict()


def ensure_group(group_name):
    group = Group.query.filter_by(name=group_name).scalar()
    if group is None:
        group = Group(name=group_name, secret=hash_password(uuid.uuid4()))
        db.session.add(group)
    return group


def create_user(user_number, group_name, role):
    group = ensure_group(group_name)
    salt = hash_password(uuid.uuid4())
    user = User(number=user_number, salt=salt, password=hash_password(salt + user_number), role=role, group=group)
    db.session.add(user)
    return user


@app.route('/user/<user_number>', methods=['PUT'])
@login_required(roles=[Roles.ADMIN])
def add_user(user_number):
    data = request.get_json()
    if data is None:
        return jsonify_error(400, message='Require JSON data')

    group_name = data.get('group', "USER")
    role = data['role']
    user = User.query.filter_by(number=user_number).scalar()
    if user is None:
        user = create_user(user_number, group_name, role)
        db.session.add(user)
    else:
        user.group = ensure_group(group_name)
        user.role = role

    department_number = data.get('department_number', None)
    if department_number:
        department = Dwdm.query.filter_by(dm=department_number).scalar()
        if department is None:
            return jsonify_error(400, '部门{}不存在'.format(department_number))
        user.department = department

    user.update_from_dict(data)

    db.session.commit()
    return success()


@app.route('/user/<user_number>', methods=['DELETE'])
@login_required(roles=[Roles.ADMIN])
def delete_user(user_number):
    user = User.query.filter_by(number=user_number).scalar()
    if user is not None:
        db.session.delete(user)
        db.session.commit()

    return success()


@app.route('/init-users', methods=['GET'])
@login_required(roles=[Roles.ADMIN])
def add_users():
    groups = [
        ('4', list(range(1, 5))),
        ('5', list(range(5, 26))),
        ('27', list(range(26, 35))),
        ('35', list(range(35, 60)) + [264, 265]),
        ('60', list(range(60, 83))),
        ('83', list(range(63, 107))),
        ('107', list(range(107, 135))),
        ('135', list(range(135, 171))),
        ('171', list(range(171, 192))),
        ('219', list(range(192, 225))),
        ('225', list(range(225, 244))),
        ('244', list(range(244, 264))),
    ]

    for i, group in enumerate(groups):
        leader, members = group
        if i == 0:
            group_name = 'admin'
        else:
            group_name = str(i - 1)

        for member in members:
            user_number = str(member)
            user = User.query.filter_by(number=user_number).scalar()
            if user is None:
                if member < 5:
                    role = Roles.ADMIN
                elif user_number == leader:
                    role = Roles.GROUP_MANAGER
                else:
                    role = Roles.USER

                create_user(user_number, group_name, role)

    db.session.commit()
    return success()

